#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <stdlib.h>
#include <limits.h>
#include <signal.h>  //sigaction
#include <pthread.h>
#include <unistd.h>  //sleep
#include <errno.h>

#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include <sys/types.h>

#include "utarray.h"
#include "log.h"
#include "util.h"
#include "conf.h"
#include "sync.h"

#define MSG_QUEUE_PATH "/tmp/redis_sync_queue"

static void sig_handle (int signo)
{
	INFO ("======received signal : %d", signo);
	if (SIGTERM == signo) {
		exit(0);
	}
	if (SIGUSR1 == signo) {
		INFO ("======received signal : SIGUSR1");
        fini_sync();
        INFO("Shutdown !");
        exit(0);
	}
	if (SIGUSR2 == signo) {
		INFO ("======received signal : SIGUSR2");
	}
}

static void * signal_handle_thread_func(void * arg) {
	INFO("======signal handle thread startup ...");
	sigset_t   waitset, oset;
	siginfo_t  info;
	int        rc;
    
	pthread_t  ppid = pthread_self();
	pthread_detach(ppid);

	sigemptyset(&waitset);
	sigaddset(&waitset, SIGUSR1);
	sigaddset(&waitset, SIGUSR2);
	sigaddset(&waitset, SIGPIPE);

	while (1)  {
		rc = sigwaitinfo(&waitset, &info);
		if (rc != -1) {
			INFO("======signal_handle_thread_func fetch the signal - %d", rc);
			sig_handle(info.si_signo);
		} else {
			ERROR("======signal_handle_thread_func fetch err: %d, %s", errno, strerror(errno));
		}
	}
	INFO("======signal handle thread shutdown");
    return NULL;
}

static void print_help() {
	const char * help = "Usage: redis_sync_server [OPTIONS]\n"
	                    "     -H    the home path of this program\n"
	                    "     -d    daemonize the program\n"
	                    "     -h    print help\n"
	                    "     \n"
	                    "version : 0.1, Written by Kevin , xuhuahai@dangdang.com\n"
	                    "     \n"
	                    "example : \n"
	                    "          ./redis_sync_server -H /var/rsync -d\n"
	                    ;
	printf("%s\n", help);
}

int main(int argc, char** argv){
	if (argc == 1){
		print_help();
		exit(0);
	}
    
	int demaeon_flag = 0;
	char home_path[PATH_MAX] = {0};
	int opt;
	while ( (opt = getopt(argc, argv, "H:dh")) != -1 ) {
		switch (opt)
		{
		case 'H':
		{
			snprintf(home_path, PATH_MAX, "%s", optarg);
			break;
		}
		case 'd':
		{
			demaeon_flag = 1;
			break;
		}
		case 'h':
		{
			print_help();
			exit(0);
		}
		}
	}
    
	if ( home_path[0] == 0 ) {
		print_help();
		exit(0);
	}    
    
    char resolved_home_path[PATH_MAX] = {0};
    if (home_path[0] != '/'){
        realpath(home_path,resolved_home_path);
        snprintf (home_path, PATH_MAX, "%s", resolved_home_path);
    }
    printf("Home path : [%s]\n",home_path);
    
    if( !is_path_exist(home_path) ){
		printf("Home path do not exist\n");
		exit(-1);
    }
    
    //set env
    char env_value[PATH_MAX] = {0};
    snprintf (env_value, PATH_MAX, "SYNC_SERVER_HOME=%s", home_path);
    putenv(env_value);
    chdir(home_path);
    
    //create 'logs' directory
    char logs_path[PATH_MAX] = {0};
    snprintf (logs_path, PATH_MAX, "%s/logs", home_path);    
    mkdirs(logs_path, 0755);
    
    //init config
    char config_file_path[PATH_MAX] = {0};
    snprintf (config_file_path, PATH_MAX, "%s/etc/core.conf", home_path);
	if (config_init(config_file_path)) {
		exit(-1);
	}
    
	//daemonize
	char cwd_path[PATH_MAX] = {0};
	get_config_item("server:cwd", cwd_path, PATH_MAX, "/tmp");
	if (demaeon_flag) {
		daemonize(cwd_path);
	}    
    
	//init log
    char log_config_file_path[PATH_MAX] = {0}; 
	get_config_item("log:config_file", log_config_file_path, PATH_MAX, "./conf/log.conf");
	if ( log_init(log_config_file_path) ) {
		exit(-1);
	}
    INFO("Home path : [%s]",home_path);
    
	// Block SIGRTMIN and SIGUSR1 which will be handled in dedicated thread signal_handle_thread_func()
	// Newly created threads will inherit the pthread mask from its creator
	sigset_t bset, oset;
	sigemptyset(&bset);
	sigaddset(&bset, SIGUSR1);
	sigaddset(&bset, SIGUSR2);
	sigaddset(&bset, SIGPIPE);
	if (pthread_sigmask(SIG_BLOCK, &bset, &oset) != 0) {
		ERROR("Set pthread mask failed");
		exit(-1);
	}
	pthread_t tid1;
    pthread_attr_t attr;
	pthread_attr_init (&attr);
	pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); 
	if (pthread_create(&tid1, &attr, ( void* (*)(void*) )signal_handle_thread_func, NULL)) {
		ERROR("signal_handle_thread_func create error : %s", strerror(errno) );
		exit(-1);
	}
	INFO("signal_handle_thread_func create successfully");
    
	//write pid
	char pid_file_path[PATH_MAX] = {0};
	get_config_item("server:pid_file", pid_file_path, PATH_MAX, "./logs/sync.pid");
	write_pid(pid_file_path);
	INFO("Written pid to %s", pid_file_path);
    
    INFO("Redis Replication Server Startup !");
    
    //initialize 
    if(init_sync()<0){
		ERROR("init_sync failed");
		exit(-1);
    }
    
    //exit main thread don't effect its child threads
    INFO("main thread enter loop");
    while(1){
        sleep(60*60);
    }
    
    return 0;
}


